using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
using BreukTrainerOnline.Models;
using BreukTrainerOnline.Model;
using System.Diagnostics;

namespace BreukTrainerOnline.Controllers
{
    [HandleError]
    public class BreukTrainerController : Controller
    {
        private static BreukTrainerRepository repo = new BreukTrainerRepository();
        private static Random random = new Random((int)DateTime.Now.Ticks);
        public static readonly IEnumerable<int> select3 = new List<int>{{1},{2},{3}};
        public static SelectList selectList3
        {
            get { return new SelectList(select3); }
        }
        public static readonly IEnumerable<int> select5 = new List<int> { { 1 }, { 2 }, { 3 }, { 4 }, { 5 } };
        public static SelectList selectList5
        {
            get { return new SelectList(select5); }
        }

        public static readonly IEnumerable<string> klassen = new List<string>(repo.GetKlassenLijst());
        public static SelectList KlassenList
        {
            get { return new SelectList(klassen); }
        }

        public ActionResult NotFound()
        {
            return View();
        }
        public ActionResult Error()
        {
            return View();
        }

        //
        // GET: /BreukTrainer/ViewOpdrachten
        public ActionResult ViewOpdrachten()
        {
            //Errors opvangen van redirects
            var previousModelState = TempData["ModelState"] as ModelStateDictionary;
            if (previousModelState != null)
            {
                foreach (KeyValuePair<string, ModelState> kvp in previousModelState)
                    if (!ModelState.ContainsKey(kvp.Key))
                        ModelState.Add(kvp.Key, kvp.Value);
            }

            var opdrachten = repo.GetOpdrachten();
            return View(opdrachten);
        }

        //
        // GET: /BreukTrainer/ViewOpdrachtDetails/($)
        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult ViewOpdrachtDetails(long? id)
        {
            if (id == null)
            {
                var opdrachtDetails = repo.GetOpdrachtDetails();
                return View(opdrachtDetails);
            }
            else
            {
                long id2 = id ?? 1;
                Opdracht o = repo.GetOpdrachtByID(id2);
                return View("ViewDetailsOpdracht", o);
            }
        }

        [AcceptVerbs(HttpVerbs.Get)]
        [Authorize(Roles="Admin")]
        public ActionResult DeleteOpdracht(long id)
        {
            repo.DeleteOpdracht(id);
            return RedirectToAction("ViewOpdrachten");
        }

        [AcceptVerbs(HttpVerbs.Get)]
        [Authorize(Roles="Admin,Leerling")]
        public ActionResult ViewResultaatOpdracht(long id)
        {
            Opdracht o = repo.GetOpdrachtByID(id);
            return View(o);
        }

        [AcceptVerbs(HttpVerbs.Get)]
        [Authorize(Roles="Admin")]
        public ActionResult ViewDetailsResultaat(long OpdrachtID, long LeerlingID)
        {
            LeerlingOpdracht lo = repo.GetLeerlingOpdracht(OpdrachtID, LeerlingID);
            return View(lo);            
        }

        // POST: /BreukTrainer/NieuweOpdracht
        [Authorize(Roles = "Admin")]
        public ActionResult NieuweOpdracht()
        {
            ViewData["select3"] = selectList3;
            ViewData["select5"] = selectList5;
            ViewData["klassen"] = KlassenList;
            return View();
        }
        [AcceptVerbs(HttpVerbs.Post)]
        [Authorize(Roles = "Admin")]
        public ActionResult NieuweOpdracht([Bind(Exclude = "OpdrachtID,Status")] Opdracht nieuweOpdracht, string Klas)
        {
            if (!ValidateNieuweOpdracht(nieuweOpdracht)) return View();
            nieuweOpdracht.Status = false;
            repo.AddOpdracht(nieuweOpdracht);
            repo.AddKlasToOpdracht(Klas, nieuweOpdracht);
            return RedirectToAction("Breukopdrachten",new {id=nieuweOpdracht.OpdrachtID});
        }

        // POST: /BreukTrainer/Breukopdrachten/($)
        [Authorize(Roles = "Admin")]
        public ActionResult Breukopdrachten(long? id, string AantalBreuken, string Bovengrens,string Ondergrens)
        {
            if (id == null)
            {
                ModelState.AddModelError("OpdrachtID", "Er is geen OpdrachtID.");
                TempData["ModelState"] = ModelState;
                return RedirectToAction("ViewOpdrachten");
            }
            else
            {
                var previousModelState = TempData["ModelState"] as ModelStateDictionary;
                if (previousModelState != null)
                {
                    foreach (KeyValuePair<string, ModelState> kvp in previousModelState)
                        if (!ModelState.ContainsKey(kvp.Key))
                            ModelState.Add(kvp.Key, kvp.Value);
                }
                
                Opdracht o = repo.GetOpdrachtByID(id ?? 1);
                return View("Breukopdrachten", o);
            }
        }

        /*[AcceptVerbs(HttpVerbs.Post)]
        [Authorize(Roles = "Admin")]
        public ActionResult Breukopdrachten(long? id,[Bind(Exclude = "OpdrachtDetailID,OpdrachtID")] OpdrachtDetail nieuweDetailOpdracht)
        {
            if (id == null)
            {
                ModelState.AddModelError("OpdrachtID", "Er is geen OpdrachtID.");
                TempData["ModelState"] = ModelState;
                return RedirectToAction("ViewOpdrachten");
            }
            else
            {
                //TODO:OpgaveTekst en OplossingTekst controleren met een regex
                //TODO:OpgaveTekst uitrekenen
                if (ValidateOpdrachtDetail(nieuweDetailOpdracht))
                {
                    nieuweDetailOpdracht.OpdrachtID = id ?? 1;
                    repo.AddDetailOpdracht(nieuweDetailOpdracht);
                }
                Opdracht o = repo.GetOpdrachtByID(id ?? 1);
                return View("Breukopdrachten", o);
            }
        }*/

        [AcceptVerbs(HttpVerbs.Post)]
        [Authorize(Roles = "Admin")]
        public ActionResult GenereerBreuken(long? id, string AantalBreuken, /*string AantalOpgaves,*/ string Ondergrens, string Bovengrens)
        {
            if (id == null)
            {
                ModelState.AddModelError("OpdrachtID", "Er is geen OpdrachtID.");
                TempData["ModelState"] = ModelState;
                return RedirectToAction("ViewOpdrachten");
            }
            else
            {
                if (ValidateGenereerBreuken(AantalBreuken, /*AantalOpgaves,*/ Bovengrens, Ondergrens))
                {
                    
                        repo.AddDetailsOpdracht(GenereerRandomDetails(int.Parse (AantalBreuken), /*int.Parse(AantalOpgaves),*/ int.Parse(Ondergrens), int.Parse(Bovengrens), id ?? 1));
                    
                }
                else
                {
                    TempData["ModelState"] = ModelState;
                }
                return RedirectToAction("Breukopdrachten", new { id = id });
            }
        }
        private List<OpdrachtDetail> GenereerRandomDetails(int aantalBreuken, /*int aantalOpgaves,*/ int ondergrens, int bovengrens,long id)
        {
            OpgaveController opgaveController = new OpgaveController(4, aantalBreuken);
            for (int i = 0; i < aantalBreuken; i++)
            {
                opgaveController.Add(Breuk.RandomBreuk(ondergrens, bovengrens));
            }
            opgaveController.BasicOpgaves();
            List<OpdrachtDetail> details = new List<OpdrachtDetail>();
            
            for (int i = 0; i < opgaveController.AantalOpgaves; i++)
            {
                OpdrachtDetail od = new OpdrachtDetail();
                od.OpdrachtID = id;
                od.OpgaveTekst = opgaveController.ToonOpgave(i);
                od.OplossingTekst = opgaveController.ToonOplossing(i);
                details.Add(od);
            }

            return details;
        }

        // POST: /BreukTrainer/LeerlingenKiezen/($)
        [Authorize(Roles = "Admin")]
        public ActionResult LeerlingenKiezen(long? id)
        {
            if (id == null)
            {
                ModelState.AddModelError("OpdrachtID", "Er is geen OpdrachtID.");
                TempData["ModelState"] = ModelState;
                return RedirectToAction("ViewOpdrachten");
            }
            else
            {
                var leerlingen = repo.GetLeerlingen();
                ViewData["OpdrachtID"] = id;
                return View("LeerlingenKiezen", leerlingen);
            }
        }
        [AcceptVerbs(HttpVerbs.Post)]
        [Authorize(Roles = "Admin")]
        public ActionResult LeerlingenKiezen(long? id, [Bind(Exclude = "LeerlingID")] List<LeerlingOpdracht> leerlingenopdracht)
        {
            if (id == null)
            {
                ModelState.AddModelError("OpdrachtID", "Er is geen OpdrachtID.");
                TempData["ModelState"] = ModelState;
                return RedirectToAction("ViewOpdrachten");
            }
            else
            {
                var leerlingen = repo.GetLeerlingen();
                return View("LeerlingenKiezen", leerlingen);
            }
        }

        // POST: /BreukTrainer/UitvoerenOpdracht/($)
        [Authorize(Roles = "Leerling")]
        public ActionResult UitvoerenOpdracht(long? id)
        {
            if (id == null)
            {
                ModelState.AddModelError("OpdrachtID", "Er is geen OpdrachtID.");
                TempData["ModelState"] = ModelState;
                return RedirectToAction("ViewOpdrachten");
            }
            else
            {
                var opdracht = repo.GetOpdrachtByID(id ?? 1);
                if (opdracht.LeerlingOpdrachts.Count() == 0)
                {
                    ModelState.AddModelError("Aantal", "Er zijn geen leerlingen ingeschreven voor deze opdracht.");
                    TempData["ModelState"] = ModelState;
                    return RedirectToAction("ViewOpdrachten");
                }
                return View("UitvoerenOpdracht", opdracht);
            }
        }
        [AcceptVerbs(HttpVerbs.Post)]
        [Authorize(Roles = "Leerling")]
        public ActionResult UitvoerenOpdrachtLeerling(long? id, long? leerlingid, int? Index, [Bind(Exclude = "LeerlingOpdrachtDetailID")] List<LeerlingOpdrachtDetail> nieuweOplossingen)
        {
            if (id == null)
            {
                ModelState.AddModelError("OpdrachtID", "Er is geen OpdrachtID.");
                TempData["ModelState"] = ModelState;
                return RedirectToAction("ViewOpdrachten");
            }
            else
            {
                var opdracht = repo.GetOpdrachtByID(id ?? 1);
                //add oplossing
                if (nieuweOplossingen != null)
                {
                    for (int i = 0; i < nieuweOplossingen.Count(); i++)
                    {
                        nieuweOplossingen.ElementAt(i).LeerlingID = leerlingid ?? 1;
                        nieuweOplossingen.ElementAt(i).OpdrachtDetailID = opdracht.OpdrachtDetails.ElementAt(i).OpdrachtDetailID;
                        nieuweOplossingen.ElementAt(i).fout = Breuk.Parse(nieuweOplossingen.ElementAt(i).AntwoordTekst).Equals(Breuk.Parse(opdracht.OpdrachtDetails.ElementAt(i).OplossingTekst));
                    }
                    repo.addLeerlingOpdrachtDetails(nieuweOplossingen);
                    Index++;
                    ViewData["Leerling"] = opdracht.LeerlingOpdrachts.ElementAt(Index ?? 0).Leerling;
                    ViewData["leerlingid"] = opdracht.LeerlingOpdrachts.ElementAt(Index ?? 0).Leerling.LeerlingID;
                    ViewData["Index"] = Index;
                }
                else
                {
                    ViewData["Leerling"] = opdracht.LeerlingOpdrachts.ElementAt(Index ?? 0).Leerling;
                    ViewData["leerlingid"] = opdracht.LeerlingOpdrachts.ElementAt(Index ?? 0).Leerling.LeerlingID;
                    ViewData["Index"] = 0;
                }
                if(Index <= (opdracht.LeerlingOpdrachts.Count))
                {
                    opdracht.Status = true;
                    return View("UitvoerenOpdrachtLeerling", opdracht) ;
                }
                else
                {
                    return RedirectToAction("ViewOpdrachten");
                }
            }
        }

        #region Validation Methods
        private bool ValidateNieuweOpdracht(Opdracht nieuweOpdracht)
        {
            if (nieuweOpdracht.Moeilijkheidsgraad > 3 && nieuweOpdracht.Moeilijkheidsgraad < 1)
            {
                ModelState.AddModelError("Moeilijkheidsgraad", "De moeilijkheidsgraad is incorrect.");
            }
            if (nieuweOpdracht.MaxScore > 5 && nieuweOpdracht.MaxScore < 1)
            {
                ModelState.AddModelError("MaxScore", "De max score is incorrect.");
            }
            if (nieuweOpdracht.Tijdslimiet < 10)
            {
                ModelState.AddModelError("Tijdslimiet", "De tijdslimiet is lager dan 10 seconden.");
            }
            if (nieuweOpdracht.Datum == null)
            {
                ModelState.AddModelError("Datum", "Gelieve een datum in te geven.");
            }
            return ModelState.IsValid;
        }

        private bool ValidateOpdrachtDetail(OpdrachtDetail nieuweDetailOpdracht)
        {
            if (nieuweDetailOpdracht.OpgaveTekst == "")
            {
                ModelState.AddModelError("OpgaveTekst", "Gelieve iets in te vullen als opgave.");
            }
            if (nieuweDetailOpdracht.OplossingTekst == "")
            {
                ModelState.AddModelError("OplossingTekst", "Gelieve iets in te vullen als oplossing.");
            }
            return ModelState.IsValid;
        }

        private bool ValidateGenereerBreuken(string AantalBreuken, /*string AantalOpgaves,*/ string Bovengrens, string Ondergrens)
        {
            if (String.IsNullOrEmpty(AantalBreuken))
            {
                ModelState.AddModelError("AantalBreuken", "Gelieve een juiste aantal in te vullen als aantal breuken");
            }
            else
            {
                try
                {
                    int aBreuken = int.Parse(AantalBreuken);
                    if (aBreuken < 2 || aBreuken > 11)
                    {
                        ModelState.AddModelError("AantalBreuken", "Gelieve een aantal in te vullen groter dan 1 en kleiner dan 11");
                    }
                }
                catch (Exception ex)
                {
                    ModelState.AddModelError("AantalBreuken", "Gelieve een getal in te vullen als aantal breuken");
                }
            }
            /*if (String.IsNullOrEmpty(AantalOpgaves))
            {
                ModelState.AddModelError("AantalOpgaves", "Gelieve een juiste aantal in te vullen.");
            }
            else
            {
                try
                {
                    int aOpgaves = int.Parse(AantalOpgaves);
                    if (aOpgaves < 1 || aOpgaves > 21)
                    {
                        ModelState.AddModelError("AantalOpgaves", "Gelieve een aantal in te vullen groter dan 0 en kleiner dan 21");
                    }
                }
                catch (Exception ex)
                {
                    ModelState.AddModelError("AantalOpgaves", "gelieve een getal in te vullen");
                }
            }*/
            if (String.IsNullOrEmpty(Bovengrens))
            {
                ModelState.AddModelError("Bovengrens", "Gelieve een bovengrens in te vullen.");
                try
                {
                    int b = int.Parse(Bovengrens);
                }
                catch
                {
                    ModelState.AddModelError("Bovengrens", "Gelive een getal in te vullen als bovengrens");
                }
            }
            if (String.IsNullOrEmpty(Ondergrens))
            {
                ModelState.AddModelError("Ondergrens", "Gelieve een ondergrens in te vullen.");
                try
                {
                    int o = int.Parse(Ondergrens);
                }
                catch
                {
                    ModelState.AddModelError("Ondergrens", "Gelive een getal in te vullen als ondergrens");
                }
            }
            if (ModelState.IsValid)
            {
                int onder = int.Parse(Ondergrens);
                int boven = int.Parse(Bovengrens);
                if (onder >= boven)
                {
                    ModelState.AddModelError("Ondergrens", "Gelieve een kleinere ondergrens in te vullen dan bovengrens");
                    ModelState.AddModelError("Bovengrens", "Gelieve een grotere ondergrens in te vullen dan ondergrens");
                }
            }
            
            return ModelState.IsValid;
        }
        #endregion

    }
}
